require 'middleclass'
require 'Display'
require 'MathUtils'
require 'Gravity'
require 'Bug'
require "Vector2D" 
require 'Particle'

Player = class('Player', Display)
--
Player.static.RUN = 0
Player.static.JUMP = 1
Player.static.FLY = 2
Player.static.DEAD = 3

function Player:initialize(imageSheet, sheet, x, y)
    -- init body
    local body = display.newCircle(x, y, 12)
    body:setFillColor( 255, 0, 0 )
    body.isVisible = false
    physics.addBody(body, "dynamic", { density = 0.2, friction = 0.0, bounce = 0.0, radius = 12 })
    -- super init
    --[[
    local sequenceData = {
        { name = "run", start=1, count=8, time=800 },
        { name = "jump", start=9, count=9, time=800 },
        { name = "fly", start=9, count=3, time=800 },
    }
    ]]--
    local sequenceData = {
        { name = "run", start=3, count=2, time=250 },
        { name = "jump", start=3, count=2, time=400 },
        { name = "fly", start=1, count=2, time=800 },
    }
    local animation = display.newSprite( imageSheet, sequenceData )
    --animation:scale(0.9, 0.9)
    animation:scale(0.3, 0.3)
    --animation.yReference = -10
    animation:setSequence("jump")
    animation:play()

    Display.initialize(self, body, animation) 
    -- special fields
    self.mode = Player.FLY
    self.planet = nil
    self.radio = 7
    self.colision = 0
    self.pressTimer = nil
    self.direction = MathUtils.LEFT
    self.smokeVector = nil
    
    --platform vector
    self.pVector = nil
    self.pCoef = 0
    self.pRotation = nil
    
    --collision listener
    self:addCollisionListener()
    --pre collision listener
    self:addPreCollisionListener()
    --touch listener
    Runtime:addEventListener("touch", self)
end

function Player:touch(event)
    if (event.phase == "began") then
        if (self.mode == Player.RUN ) then                
            self.mode = Player.JUMP
            Gravity.jumpI(self)
            self.colision = 10
            local function listener( event )               
                Gravity.jump(self)
                self.planet = nil
                self.mode = Player.FLY
            end
            if(player.pVector == nil)then
                self.pressTimer = timer.performWithDelay(220, listener )
            end
        end
    elseif (event.phase == "ended") then
        if self.pressTimer then
            timer.cancel(self.pressTimer)
            self.pressTimer = nil
        end
    end
end

function Player:collision(event)
    if (event.phase == "began") then
        if(event.other.cont.class.name == 'Planet')then
            if(self.colision == 0)then
                self.mode = Player.RUN
                self.planet = event.other.cont
            end 
            -- level complete if it is the last planet
            if(event.other.cont.isFinal)then
                Runtime:dispatchEvent( {name = 'levelComplete'} )
            end
        elseif(event.other.cont.class.name == 'Collector' )then
            Runtime:dispatchEvent( {name = 'star'} )
            event.other:removeSelf( )   
        elseif(event.other.cont.class.name == 'Bug' )then
            if(self.mode == Player.RUN)then
                Runtime:dispatchEvent( {name = 'live'} )
                --self.mode = Player.DEAD 
            else
                self.planet = event.other.cont.planet
                self.mode = Player.JUMP
                Gravity.jumpI(self)
                Gravity.jumpI(self)
                self.body.parent:insert(Particle.getParticle(event.other.x,event.other.y,0.8, 20))
                event.other:removeSelf()          
            end
        elseif(event.other.cont.class.name == 'BouncyBlock' )then
           Runtime:dispatchEvent( {name = 'live'} )
           self.body.parent:insert(Particle.getParticle(event.other.x,event.other.y,0.8, 50))
           event.other:removeSelf()          
       end  
    elseif (event.phase == "ended") then
    end
end

--revisar logica
function Player:preCollision(event)
    if ( event.other.cont.class.name == 'PlatformTrans') then
        if(MathUtils.isOver(self,event.other.cont))then
        --if(event.other.y + event.other.height/2 > self.body.y +  self.body.height)then
             self.mode = Player.RUN           
        else
           event.contact.isEnabled = false
        end
    end
    if ( event.other.cont.class.name == 'Platform') then
         self.mode = Player.RUN
    end
end

function Player:update(game)
    --sincronizacion con sprite
    self.sprite.x = self.body.x
    self.sprite.y = self.body.y
    
    --rotation
    local rotation
    local direction = nil
    if(self.planet ~= nil and self.pRotation == nil)then
        rotation = MathUtils.angleBetween ( self.planet:getVector(), self:getVector() )
        if(self.mode == Player.RUN)then
            direction = MathUtils.direction( self.planet:getVector(), self:getVector(), self:getLinearVelocityVec())
        end
    elseif(self.pRotation ~= nil)then
        rotation = self.pRotation   
    else
        rotation = MathUtils.angleBetween ( { x = 0, y = 1 }, self:getLinearVelocityVec() )
    end
    self.sprite.rotation = rotation
    
    local function directionListener( event )
        local direction = MathUtils.direction(self.planet:getVector(), self:getVector(), self:getLinearVelocityVec())
        if(direction ~= nil and self.direction ~= direction)then
            self.direction = direction
            self.sprite:scale(-1,1)
        end
    end
    
    --direction (en el futuro cambiar solo al aterrizar, modo landing)
    if(direction ~= nil and self.direction ~= direction)then
        self.pressTimer = timer.performWithDelay(200, directionListener )      
    end
    
    --control de colision
    if(self.colision>0)then
        self.colision = self.colision -1
    end        
    
    --change animations
    if(self.mode == Player.RUN)then
        if(self.sprite.sequence ~= "run")then
            self.sprite:setSequence("run")
            self.sprite:play()
        end
    end
    if(self.mode == Player.JUMP)then      
        if(self.sprite.sequence ~= "jump")then
            self.sprite:setSequence("jump")
            self.sprite:play()
        end
    end
    if(self.mode == Player.FLY)then
        --smoke tail
        local function smokeListener(event)
            self.body.parent:insert(Particle.getParticle(self.somokeVector.x,self.somokeVector.y,0.3, 10))
            self.somokeVector = nil
        end
        if(self.somokeVector == nil)then
            self.somokeVector = self:getVector()
            timer.performWithDelay(100, smokeListener )        
        end
        if(self.sprite.sequence ~= "fly")then
            self.sprite:setSequence("fly")
            self.sprite:play()
        end
    end
    
    --velocidad en planeta
    Gravity.speed(self)
    Gravity.applyGravity(self, game)    
end

function Player:clean()
    print('cleanP')
    Runtime:removeEventListener("touch", self)
    --self.sprite:removeSelf()
end
